package com.lyy.java_chatroom.api;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.lyy.java_chatroom.component.OnlineUserManager;
import com.lyy.java_chatroom.constant.Constant;
import com.lyy.java_chatroom.mapper.MessageMapper;
import com.lyy.java_chatroom.mapper.MessageSessionMapper;
import com.lyy.java_chatroom.model.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;
import java.sql.Timestamp;
import java.util.List;


/**
 * 用于处理 WebSocket 连接的建立、消息接收、异常处理和连接关闭等事件。
 * 当有新消息时，会将消息转发给相关用户，并将消息存储到数据库中
 */
@Component
public class WebSocketApi extends TextWebSocketHandler {

    @Autowired
    private OnlineUserManager onlineUserManager;//用于管理在线用户的会话信息

    private ObjectMapper objectMapper=new ObjectMapper();//用于JSON数据的序列化和反序列化

    @Autowired
    private MessageSessionMapper messageSessionMapper;

    @Autowired
    private MessageMapper messageMapper;

    //webSocket连接建立时，从WebSocketSession中获取用户信息，并将用户标记在线
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        System.out.println("websocket 连接成功！");
        try {
            User user=(User) session.getAttributes().get(Constant.USER_SESSION_KEY);
            onlineUserManager.online(user.getUserId(),session);
        }catch (NullPointerException e){
            e.printStackTrace();
        }

    }

    //收到文本消息时，解析消息内容，并根据消息类型进行相应处理
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        System.out.println("websocket 收到消息！");
        try {
            //1、发送者
            User user=(User) session.getAttributes().get(Constant.USER_SESSION_KEY);
            //2、MessageRequest{type,sessionId,content}
            MessageRequest req=objectMapper.readValue(message.getPayload(),MessageRequest.class);
            if ("message".equals(req.getType())){
                //处理消息请求
                handleMessage(user,req);
            }
        }catch (NullPointerException e){
            e.printStackTrace();
        }
    }

    //当 WebSocket连接出现异常时，将用户标记为离线
    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        System.out.println("websocket 连接异常！");
        try {
            User user=(User) session.getAttributes().get(Constant.USER_SESSION_KEY);
            onlineUserManager.offline(user.getUserId(),session);
        }catch (NullPointerException e){
            e.printStackTrace();
        }
    }

    //当 WebSocket连接关闭时，将用户标记为离线
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        System.out.println("websocket 连接关闭！");
        try {
            User user=(User) session.getAttributes().get(Constant.USER_SESSION_KEY);
            onlineUserManager.offline(user.getUserId(),session);
        }catch (NullPointerException e){
            e.printStackTrace();
        }
    }

    /**
     * 处理请求消息，构造响应消息，将消息转发给相关用户，并将消息存储进数据库中
     * @param fromUser
     * @param req: type,sessionId,content
     * @throws IOException
     */
    public void handleMessage(User fromUser, MessageRequest req) throws IOException {

        //1、构造MessageResponse {type,fromId,fromName,sessionId,content,postTime}
        MessageResponse resp=new MessageResponse();
        resp.setType("message");
        resp.setFromId(fromUser.getUserId());
        resp.setFromName(fromUser.getUserName());
        resp.setContent(req.getContent());
        resp.setSessionId(req.getSessionId());
        String respJson=objectMapper.writeValueAsString(resp);
        System.out.println("[handlerMessage] resp:"+respJson);

        //2、根据请求中的sessionId在数据库中找到相关所有userId(刨除自身登录用户)
        List<Friend> friends=messageSessionMapper.getFriendBySessionId(req.getSessionId(), fromUser.getUserId());

        //3、把自己加入这个列表
        Friend myself=new Friend();
        myself.setFriendId(fromUser.getUserId());
        myself.setFriendName(fromUser.getUserName());
        friends.add(myself);
        System.out.println("[handlerMessage] 要转发给哪些人："+friends);

        //4、根据每个userId找到对应的WebSocketSession，发送数据
        for(Friend friend:friends){
            WebSocketSession webSocketSession=onlineUserManager.getSession(friend.getFriendId());
            if (webSocketSession==null)
                continue;//如果用户不在线就不用管了，直接存数据库，下次李四上线通过查找历史消息查到最新消息
            webSocketSession.sendMessage(new TextMessage(respJson));
        }

        //5、把消息写入数据库
        Message message=new Message();
        message.setFromId(resp.getFromId());
        message.setSessionId(resp.getSessionId());
        message.setContent(resp.getContent());
        messageMapper.add(message);
    }
}
